P11-2. Grafana 상관분석과 Kiali 토폴로지 - 실습 검증
P11-2. Grafana 상관분석과 Kiali 토폴로지 - 실습 검증
monitoring네임스페이스에 **Grafana (v11.5.2)**를 배포하며, 코드형 선언적 프로비저닝(datasources.yaml)을 통해 VictoriaMetrics(Metrics) · Loki(Logs) · Tempo(Traces) 3대 데이터소스와 **상관분석 점프 규칙(tracesToLogsV2,derivedFields,exemplarTraceIdDestinations)**을 한 번에 자동 구성한다.istio-system네임스페이스에 **Kiali Server (v2.33.0)**를 Helm으로 배포하고, 외부 VictoriaMetrics·Grafana·Tempo 엔드포인트와 연동하여 Ambient Mesh(ztunnel+waypoint) 및 외부 PostgreSQL 18 VM(pg-vm.mesh.internal)까지의 실시간 서비스 토폴로지 그래프 JSON과 **Istio CRD 정합성 검증 상태(WaypointBound)**를 실측한다.kubectl port-forward를 통해 로컬 브라우저에서 Grafana Explore 화면과 Kiali 대시보드에 접속하여 Metrics → Traces → Logs 3단계 상관분석 워크플로우를 검증한다.
1. 사전 환경 점검
Part 08~10에서 구축한 monitoring 네임스페이스의 수집기(alloy) 및 3대 백엔드 스토리지(vmsingle, loki, tempo)가 모두 정상 동작 중인지 확인한다.
kubectl get pods,svc -n monitoring
NAME READY STATUS RESTARTS AGE
pod/alloy-659d8d98d4-68896 1/1 Running 0 10m
pod/loki-77f5c85fd7-fssmd 1/1 Running 0 10m
pod/tempo-7b97b8b6f4-5gbcx 1/1 Running 0 10m
pod/vmsingle-7b77cc877c-5ds97 1/1 Running 0 16m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/alloy ClusterIP 10.96.182.114 <none> 12345/TCP,4317/TCP,4318/TCP 10m
service/loki ClusterIP 10.96.105.192 <none> 3100/TCP 10m
service/tempo ClusterIP 10.96.239.141 <none> 3200/TCP,4317/TCP,4318/TCP 10m
service/vmsingle ClusterIP 10.96.135.209 <none> 8428/TCP 16m
2. Grafana 11.5 배포 및 3대 데이터소스 상관분석 자동 프로비저닝
2.1 매니페스트 작성 ($HOME\mesh-study\part11-grafana.yaml)
웹 UI에서 수동으로 데이터소스를 클릭해 등록하는 대신, /etc/grafana/provisioning/datasources/datasources.yaml ConfigMap을 마운트하여 컨테이너 기동 즉시 VictoriaMetrics · Loki · Tempo와 상호 참조 링크(uid: victoriametrics, uid: loki, uid: tempo)가 자동 구성되도록 작성한다.
@'
apiVersion: v1
kind: ConfigMap
metadata:
name: grafana-datasources
namespace: monitoring
data:
datasources.yaml: |
apiVersion: 1
datasources:
- name: VictoriaMetrics
type: prometheus
uid: victoriametrics
access: proxy
url: http://vmsingle.monitoring.svc.cluster.local:8428
isDefault: true
jsonData:
httpMethod: POST
exemplarTraceIdDestinations:
- name: trace_id
datasourceUid: tempo
- name: Loki
type: loki
uid: loki
access: proxy
url: http://loki.monitoring.svc.cluster.local:3100
jsonData:
derivedFields:
- datasourceUid: tempo
matcherRegex: '"([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})"'
name: RequestID
url: '${__value.raw}'
- name: Tempo
type: tempo
uid: tempo
access: proxy
url: http://tempo.monitoring.svc.cluster.local:3200
jsonData:
tracesToLogsV2:
datasourceUid: loki
spanStartTimeShift: '-1m'
spanEndTimeShift: '1m'
filterByTraceID: false
filterBySpanID: false
customQuery: true
query: '{namespace="part1-demo"}'
serviceMap:
datasourceUid: victoriametrics
nodeGraph:
enabled: true
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: grafana
namespace: monitoring
labels:
app: grafana
spec:
replicas: 1
selector:
matchLabels:
app: grafana
template:
metadata:
labels:
app: grafana
spec:
containers:
- name: grafana
image: grafana/grafana:11.5.2
ports:
- containerPort: 3000
name: http
env:
- name: GF_AUTH_ANONYMOUS_ENABLED
value: "true"
- name: GF_AUTH_ANONYMOUS_ORG_ROLE
value: "Admin"
- name: GF_SECURITY_ALLOW_EMBEDDING
value: "true"
volumeMounts:
- name: datasources
mountPath: /etc/grafana/provisioning/datasources
volumes:
- name: datasources
configMap:
name: grafana-datasources
---
apiVersion: v1
kind: Service
metadata:
name: grafana
namespace: monitoring
labels:
app: grafana
spec:
selector:
app: grafana
ports:
- name: http
port: 3000
targetPort: 3000
'@ | Set-Content -Path "$HOME\mesh-study\part11-grafana.yaml" -Encoding UTF8
kubectl apply -f "$HOME\mesh-study\part11-grafana.yaml"
kubectl rollout status deployment/grafana -n monitoring
uid고정 (victoriametrics,loki,tempo): Grafana가 랜덤 UID를 생성하도록 두면 데이터소스 간 점프 설정(datasourceUid: loki,datasourceUid: tempo)이 깨진다. 반드시 명시적인uid를 지정해야 한다.GF_AUTH_ANONYMOUS_ENABLED: "true"&GF_SECURITY_ALLOW_EMBEDDING: "true": 로컬 실습 편의성과 Kiali 대시보드 내 Grafana 차트 임베딩 연동을 위해 익명 Admin 접근 및 iframe 임베딩을 허용했다.tracesToLogsV2: Tempo의 개별 Span에서Logs for this span을 클릭했을 때 해당 Span의 시작/종료 시각(±1m)을 기준으로{namespace="part1-demo"}스트림의 Waypoint 및 애플리케이션 로그를 즉시 분할 창에 띄운다.
2.2 Grafana API를 통한 프로비저닝 검증
study-client 파드에서 Grafana의 /api/datasources REST API를 호출하여 3개 데이터소스와 상관분석 JSON 설정이 정확히 등록되었는지 확인한다.
kubectl exec -n part1-demo study-client -- curl -s http://grafana.monitoring.svc.cluster.local:3000/api/datasources
실제 응답 결과 (요약 정렬):
[
{
"id": 2,
"uid": "loki",
"name": "Loki",
"type": "loki",
"url": "http://loki.monitoring.svc.cluster.local:3100",
"jsonData": {
"derivedFields": [
{
"datasourceUid": "tempo",
"matcherRegex": "\"([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\"",
"name": "RequestID",
"url": "{__value.raw}"
}
]
},
"readOnly": true
},
{
"id": 3,
"uid": "tempo",
"name": "Tempo",
"type": "tempo",
"url": "http://tempo.monitoring.svc.cluster.local:3200",
"jsonData": {
"nodeGraph": { "enabled": true },
"serviceMap": { "datasourceUid": "victoriametrics" },
"tracesToLogsV2": {
"customQuery": true,
"datasourceUid": "loki",
"filterBySpanID": false,
"filterByTraceID": false,
"query": "{namespace=\"part1-demo\"}",
"spanEndTimeShift": "1m",
"spanStartTimeShift": "-1m"
}
},
"readOnly": true
},
{
"id": 1,
"uid": "victoriametrics",
"name": "VictoriaMetrics",
"type": "prometheus",
"url": "http://vmsingle.monitoring.svc.cluster.local:8428",
"isDefault": true,
"jsonData": {
"exemplarTraceIdDestinations": [
{ "datasourceUid": "tempo", "name": "trace_id" }
],
"httpMethod": "POST"
},
"readOnly": true
}
]
3. Kiali Server (v2.33.0) 설치 및 LGTM 스택 연동
3.1 Helm을 이용한 Kiali Server 배포
Kiali가 기본적으로 찾는 http://prometheus.istio-system:9090 대신 우리가 구축한 monitoring 네임스페이스의 VictoriaMetrics (:8428), Grafana (:3000), **Tempo (:3200 / :4317)**를 바라보도록 external_services 파라미터를 주입하여 설치한다.
helm repo add kiali https://kiali.org/helm-charts
helm repo update
helm upgrade --install kiali-server kiali/kiali-server `
--namespace istio-system `
--set auth.strategy="anonymous" `
--set external_services.prometheus.url="http://vmsingle.monitoring.svc.cluster.local:8428" `
--set external_services.grafana.enabled=true `
--set external_services.grafana.internal_url="http://grafana.monitoring.svc.cluster.local:3000" `
--set external_services.tracing.enabled=true `
--set external_services.tracing.provider="tempo" `
--set external_services.tracing.internal_url="http://tempo.monitoring.svc.cluster.local:3200" `
--set external_services.tracing.use_grpc=false
3.2 Kiali 연동 상태 (/kiali/api/status) 실측 검증
Kiali 파드가 1/1 Running 상태가 되면 /kiali/api/status 엔드포인트를 호출해 외부 LGTM 서비스들과의 연결 상태를 확인한다.
kubectl exec -n part1-demo study-client -- curl -s http://kiali.istio-system.svc.cluster.local:20001/kiali/api/status
실제 응답 결과:
{
"status": {
"Disabled features": "",
"Kiali commit hash": "0b0d4e7e2a9eff0edf9815742794d6377ab26815",
"Kiali container version": "v2.33.0",
"Kiali state": "running",
"Kiali version": "v2.33.0"
},
"externalServices": [
{
"name": "Kubernetes-Kubernetes",
"version": "v1.31.1",
"tempoConfig": {}
},
{
"name": "Prometheus",
"version": "2.24.0",
"tempoConfig": {}
},
{
"name": "Grafana",
"version": "11.5.2",
"tempoConfig": {}
},
{
"name": "tempo",
"version": "v2.7.1",
"tempoConfig": {
"cacheCapacity": 200,
"cacheEnabled": true
}
}
],
"warningMessages": [],
"istioEnvironment": {
"istioAPIEnabled": true
}
}
externalServices배열에 Kubernetes(v1.31.1), Prometheus 호환 백엔드(VictoriaMetrics), Grafana(11.5.2), **Tempo(v2.7.1)**가 단 하나의 경고(warningMessages: [])도 없이 완벽하게 인식된 것을 확인할 수 있다.
4. Kiali 토폴로지 그래프 및 Ambient Mesh 설정 검증
4.1 트래픽 발생 및 실시간 토폴로지 그래프 (/kiali/api/namespaces/graph) 확인
study-client에서 order-api로 트래픽을 발생시킨 뒤, Kiali가 VictoriaMetrics의 istio_* 메트릭을 집계하여 생성한 실시간 토폴로지 그래프 데이터를 조회한다.
1..5 | ForEach-Object {
kubectl exec -n part1-demo study-client -- curl -s -o /dev/null http://order-api.part1-demo.svc.cluster.local/api/orders
}
Start-Sleep -Seconds 6
kubectl exec -n part1-demo study-client -- curl -s "http://kiali.istio-system.svc.cluster.local:20001/kiali/api/namespaces/graph?namespaces=part1-demo&graphType=versionedApp&duration=10m"
실제 응답 중 핵심 노드 및 엣지(Edge) 발췌:
{
"graphType": "versionedApp",
"elements": {
"nodes": [
{
"data": {
"namespace": "part1-demo",
"app": "order-api",
"healthData": {
"status": { "status": "Healthy", "totalRequestRate": 1.71 },
"workloadStatuses": [
{ "name": "order-api", "availableReplicas": 2, "desiredReplicas": 2 },
{ "name": "order-api-v2", "availableReplicas": 1, "desiredReplicas": 1 }
]
}
}
}
],
"edges": [
{
"data": {
"destPrincipal": "spiffe://cluster.local/ns/part1-demo/sa/default",
"sourcePrincipal": "spiffe://cluster.local/ns/part1-demo/sa/default",
"isMTLS": "100",
"healthStatus": "Healthy",
"traffic": {
"protocol": "tcp",
"responses": {
"-": {
"hosts": { "pg-vm.mesh.internal": "100.0" }
}
}
}
}
},
{
"data": {
"healthStatus": "Healthy",
"isMTLS": "100",
"traffic": {
"protocol": "tcp",
"responses": {
"-": {
"hosts": { "order-api.part1-demo.svc.cluster.local": "100.0" }
}
}
},
"waypoint": { "direction": "to" }
}
}
]
}
}
"isMTLS": "100"&"sourcePrincipal": "spiffe://cluster.local/ns/part1-demo/sa/default": 모든 파드 간 통신이ztunnel에 의해 100% HBONE mTLS 암호화 및 SPIFFE ID 상호 인증으로 보호되고 있다."waypoint": { "direction": "to" }:order-api및postgres-exporter로 향하는 트래픽이 L7waypoint프록시를 경유하고 있음을 Kiali가 정확히 인지한다."hosts": { "pg-vm.mesh.internal": "100.0" }: 클러스터 외부 Docker 브릿지의 PostgreSQL 18 VM(172.19.0.7:5432)으로 나가는 TCP 이그레스 트래픽까지 Kiali 토폴로지 맵의 정식 엣지(Edge)로 시각화된다!
4.2 Kiali Istio CRD 정합성 검증 (/kiali/api/namespaces/part1-demo/istio)
Kiali가 part1-demo 네임스페이스의 Istio 및 Kubernetes Gateway API 리소스들을 어떻게 검증하고 있는지 조회한다.
kubectl exec -n part1-demo study-client -- curl -s "http://kiali.istio-system.svc.cluster.local:20001/kiali/api/namespaces/part1-demo/istio"
실제 응답 결과 (핵심 상태 요약):
Gateway/waypoint:Accepted: True ("Resource accepted")Programmed: True ("Resource programmed, assigned to service(s) waypoint.part1-demo.svc.cluster.local:15008")
ServiceEntry/external-pg-se:istio.io/WaypointBound: True ("Successfully attached to waypoint part1-demo/waypoint")
WorkloadEntry/study-pg-vm-01:address: "172.19.0.7",labels: { app: "external-pg-vm", class: "vm" }PeerAuthentication/strict-mtls:mtls: { mode: "STRICT" }Telemetry/mesh-observability:tracing: otel-tracing (100%),accessLogging: envoy
5. 로컬 브라우저 UI 접속 가이드 (kubectl port-forward)
백그라운드 터미널 2개를 열어 Grafana와 Kiali 웹 UI를 로컬 PC 포트로 포워딩하면 브라우저에서 시각적으로 탐색할 수 있다.
# 1. Grafana UI 포트포워딩 (http://localhost:3000)
Start-Process powershell -ArgumentList "-NoExit", "-Command", "kubectl port-forward -n monitoring svc/grafana 3000:3000"
# 2. Kiali UI 포트포워딩 (http://localhost:20001)
Start-Process powershell -ArgumentList "-NoExit", "-Command", "kubectl port-forward -n istio-system svc/kiali 20001:20001"
- Grafana Explore (
http://localhost:3000/explore):- 상단 데이터소스에서 Tempo 선택 →
Search탭에서Service Name = order-api.part1-demo조회 - 검색된 Trace ID 클릭 → 우측 워터폴 뷰에서 Span 옆의
Logs for this span아이콘 클릭 - 화면이 좌우로 분할되며 우측 Loki 창에 해당 시각의 Waypoint Envoy Access Log가 나란히 출력되는 것을 확인!
- 상단 데이터소스에서 Tempo 선택 →
- Kiali Console (
http://localhost:20001/kiali):- 좌측 메뉴 Traffic Graph 클릭 → Namespace 드롭다운에서
part1-demo체크 - Display 옵션에서
Traffic Animation,Security (mTLS 자물쇠 아이콘),Waypoint Proxies체크
- 좌측 메뉴 Traffic Graph 클릭 → Namespace 드롭다운에서
6. 트러블슈팅 및 체크리스트
| 증상 | 원인 | 해결 방법 |
|---|---|---|
Tempo에서 Logs for this span 버튼이 비활성화됨 |
datasources.yaml의 tracesToLogsV2.datasourceUid가 실제 Loki의 uid와 불일치 |
Loki 데이터소스 정의에 명시적으로 uid: loki를 선언하고 tracesToLogsV2.datasourceUid: loki로 일치시킨다 |
Kiali Traffic Graph가 비어 있음 (Empty Graph) |
최근 시간 창(Last 1m ~ 10m) 동안 메시 내부 트래픽이 없었거나 Prometheus URL 오타 |
study-client에서 curl 요청을 5~10회 발생시키고 Kiali 우측 상단 시간 범위를 Last 10m으로 조정한다 |
Kiali Istio Config에서 KIA1102 등 잘못된 VirtualService 경고 발생 |
동일한 hosts를 대상으로 중복된 라우팅 규칙이 충돌할 때 발생 |
kubectl get vs,httproute -n part1-demo로 중복 리소스를 확인하고 하나만 남긴다 |
7. 셀프 체크 Q&A
- Q1. Grafana 프로비저닝 설정에서 각 데이터소스의
uid필드를 생략하면 어떤 문제가 발생하는가?- A1. Grafana가 기동할 때 무작위 문자열(예:
P40892A...)로uid를 자동 발급한다. 그 결과 Tempo의tracesToLogsV2나 VictoriaMetrics의exemplarTraceIdDestinations에서 참조하는datasourceUid: loki/tempo연결 고리가 끊어져 원클릭 상관분석 점프가 동작하지 않는다.
- A1. Grafana가 기동할 때 무작위 문자열(예:
- Q2. Kiali 토폴로지 그래프에서
ServiceEntry/external-pg-se가istio.io/WaypointBound: True상태를 갖는다는 것은 무슨 뜻인가?- A2. 클러스터 외부의 PostgreSQL VM(
pg-vm.mesh.internal)을 가리키는 가상 서비스가part1-demo의 L7waypoint프록시에 정상적으로 바인딩되어, 외부 DB로 나가는 이그레스 트래픽까지 Waypoint에서 메트릭·액세스 로그·트레이스로 관측 및 제어되고 있다는 뜻이다.
- A2. 클러스터 외부의 PostgreSQL VM(
네비게이션
| 이전 | 목록 | 다음 |
|---|---|---|
| ◀ Part 11 이론 | 목록으로 | Part 12 이론 ▶ |